﻿using System;
using System.Collections.Generic;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.Structure;
using iMapa.Backend;

namespace iMapa.Backend
{
    public class RunningAverage
    {
        private static RunningAverage ra =new RunningAverage();

        private  Queue<Image<Gray, Byte>> q = new Queue<Image<Gray, byte>>();
        private  int queueLength=ConfigurationConstants.RUNNIING_AVERAGE_WIDTH;
        private Image<Gray, float> runavg = new Image<Gray, float>(640, 480, new Gray(0));

        private RunningAverage(){
        }

        public static RunningAverage getInstance()
        {
            return ra;
        }


        public void clear()
        {
            q.Clear();
            runavg.Dispose();
            runavg = new Image<Gray, float>(640, 480, new Gray(0));
        }

        public Image<Gray, float> addImageToAverage(Image<Gray, Byte> frame)
        {
            if (q.Count <= queueLength - 1)
            {
                q.Enqueue(frame);
                runavg.RunningAvg(frame.Convert<Gray, float>(), 1.0 / q.Count);
                return runavg;
            }
            else
            {
                //compute avg
                Image<Gray, Byte> depImage =  q.Dequeue();
                Image<Gray, float> deprecatedImage = depImage.ConvertScale<float>(1.0 / queueLength, 0.0);
                Image<Gray, float> newImage = frame.ConvertScale<float>(1.0 / queueLength, 0.0);
                Image<Gray, float> oldrunavg = runavg;
                runavg = runavg.Sub(deprecatedImage).Add(newImage);
                
                //dispose old images
                depImage.Dispose();
                deprecatedImage.Dispose();
                newImage.Dispose();
                oldrunavg.Dispose();

                q.Enqueue(frame);
                return runavg;
            }

        }

        public Image<Gray, float> getAverage()
        {
            return runavg;
        }


    }

    public class AbsDiffFrame
    {
        private static AbsDiffFrame adf = new AbsDiffFrame();

        private Image<Gray, float> diff;
        private RunningAverage ra;

        private AbsDiffFrame()
        {
            diff = new Image<Gray, float>(640, 480, new Gray(255));
            ra = RunningAverage.getInstance();
        }

        public static AbsDiffFrame getInstance()
        {
            return adf;
        }

        public Image<Gray, float> getAbsDiffFrame()
        {
            return diff;
        }

        public Image<Gray, float> computeAbsDiffFrame(Image<Gray, Byte> frame)
        {
            Image<Gray, float> olddiff = diff;
            diff= ra.getAverage().AbsDiff(frame.Convert<Gray, float>());
            olddiff.Dispose();
            return diff;
        }

    }

    public class LastDetectedPoint
    {
        private static LastDetectedPoint ldp = new LastDetectedPoint();

        private Point? p = null;

        public Point? LastDetectedSpotPoint
        {
            get { return p; }
            set { p = value; }
        }

        private LastDetectedPoint()
        {
        }

        public static LastDetectedPoint getInstance()
        {
            return ldp;
        }

        
    }

    public class ListOfInteractMapGroups
    {
        private static ListOfInteractMapGroups singleton;
        private List<InteractMapGroup> mapgroups = InteractMapLoader.LoadInteractMaps();

        private ListOfInteractMapGroups()
        {
            
        }

        public void AddInteractMapGroup(InteractMapGroup mapgroup)
        {
            mapgroups.Add(mapgroup);
        }
        
        public static ListOfInteractMapGroups getInstance()
        {
            if (singleton == null)
            {
                singleton = new ListOfInteractMapGroups();
            }
            return singleton ;
        }


        public List<InteractMapGroup> GetAllInteractMapGroups()
        {
            return mapgroups;
        }
    }
   
}
